package jwlee.testfile;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * java.util.zip包压缩和解压缩文件zip文件
 */
public class ZipFileMerger{
	static String jarPerfix = "ja";
	static String jarPerfix_Exclude = "";

	public static void main(String[] args) throws Exception {
		String path = System.getProperty("user.dir")
		+ "\\src\\jwlee\\testfile\\";
		
//		junit.textui.TestRunner.run(ZipTest.class);
		ZipFileMerger zt = new ZipFileMerger();
//		String zipDirPath = path + "jars";
//		String zipFilePath = path + "merge.jar";
//		zt.doZip(zipDirPath, zipFilePath);
		
//		String unzipFilePath = path + "merge.jar";
//		String unzipDirPath = path + "jars";
//		zt.doUnZip(unzipFilePath, unzipDirPath);
		
		String dirPath;
//		dirPath = path + "jars";
		dirPath = "D:\\DigitalChina\\fromsvn\\framelib";
		String mergeFilePath;
//		mergeFilePath = path + "merge.jar";
		mergeFilePath = "D:\\DigitalChina\\fromsvn\\"+jarPerfix+"-merge.jar";
		zt.mergeJars(dirPath, mergeFilePath);
		System.out.println("----oooooooooooooooooooooooooooook----");
	}

	/**
	 * zip压缩功能
	 * @param zipDirPath 待压缩目录
	 * @param zipFilePath 压缩后文件
	 * @throws Exception
	 */
	public void doZip(String zipDirPath, String zipFilePath) throws IOException {
		// 压缩baseDir下所有文件，包括子目录
		List<File> fileList = FileUtil.getSubFiles(new File(zipDirPath));

		// 压缩文件名
		ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(
				zipFilePath));

		byte[] buf = new byte[1024];
		int readLen = 0;
		ZipEntry zipEntry = null;
		for (int i = 0; i < fileList.size(); i++) {
			File f = fileList.get(i);
			System.out.print("Adding: " + f.getPath() + f.getName());

			// 创建一个ZipEntry，并设置Name和其他的一些属性
			zipEntry = new ZipEntry(this.getAbsFileName(zipDirPath, f));
			zipEntry.setSize(f.length());
			zipEntry.setTime(f.lastModified());

			// 将ZipEntry加到zos中，再写入实际的文件内容
			zos.putNextEntry(zipEntry);
			
			InputStream is = new BufferedInputStream(new FileInputStream(f));
			while ((readLen = is.read(buf, 0, 1024)) != -1) {
				zos.write(buf, 0, readLen);
			}
			is.close();
			System.out.println("   done...");
		}
		zos.close();
	}

	/**
	 * unzip解压缩功能
	 * @param unzipFilePath 待解压文件
	 * @param unzipDirPath 压缩后目录
	 * @throws Exception
	 */
	public void doUnZip(String unzipFilePath, String unzipDirPath) throws IOException {
		ZipFile zipFile = new ZipFile(unzipFilePath);
		System.out.println(zipFile.getName());
		Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
		byte[] buf = new byte[1024];
		ZipEntry zipEntry = null;
		while (zipEntrys.hasMoreElements()) {
			// 从ZipFile中得到一个ZipEntry
			zipEntry = (ZipEntry) zipEntrys.nextElement();
			if (zipEntry.isDirectory()) {
				System.out.println("Dir: " + zipEntry.getName() + " skipped..");
				continue;
			}
			System.out.println("Extracting: " + zipEntry.getName() + "＼t"
					+ zipEntry.getSize() + "＼t" + zipEntry.getCompressedSize());

			// 以ZipEntry为参数得到一个InputStream，并写到OutputStream中
			File realFile = getRealFile(unzipDirPath, zipEntry.getName());
			OutputStream os = new BufferedOutputStream(new FileOutputStream(
					realFile));
			InputStream is = new BufferedInputStream(zipFile.getInputStream(zipEntry));
			int readLen = 0;
			while ((readLen = is.read(buf, 0, 1024)) != -1) {
				os.write(buf, 0, readLen);
			}
			is.close();
			os.close();
			System.out.println("Extracted: " + zipEntry.getName());
		}
		zipFile.close();
	}

	/**
	 * 给定根目录，返回一个相对路径所对应的实际文件.
	 * 
	 * @param baseDir
	 *            指定根目录
	 * @param absFileName
	 *            相对路径名，来自于ZipEntry中的name
	 * @return java.io.File 实际的文件
	 */
	private File getRealFile(String baseDir, String absFileName) {
		String[] dirs = absFileName.split("/");
		// System.out.println(dirs.length);
		File ret = new File(baseDir);
		if (dirs.length > 1) {
			for (int i = 0; i < dirs.length - 1; i++) {
				ret = new File(ret, dirs[i]);
			}
		}
		if (!ret.exists()) {
			ret.mkdirs();
		}
		ret = new File(ret, dirs[dirs.length - 1]);
		return ret;
	}

	/**
	 * 给定根目录，返回另一个文件名的相对路径，用于zip文件中的路径.
	 * 
	 * @param baseDir
	 *            java.lang.String 根目录
	 * @param realFileName
	 *            java.io.File 实际的文件名
	 * @return 相对文件名
	 */
	private String getAbsFileName(String baseDir, File realFileName) {
		File real = realFileName;
		File base = new File(baseDir);
		String ret = real.getName();
		while (true) {
			real = real.getParentFile();
			if (real == null)
				break;
			if (real.equals(base))
				break;
			else {
				ret = real.getName() + "/" + ret;
			}
		}
		return ret;
	}

	/**
	 * 合并jar包，将dirPath下的jar包合并为mergeFilePath
	 * @param dirPath 
	 * @param mergeFilePath
	 * @throws IOException 
	 * @throws Exception 
	 */
	public void mergeJars(String dirPath, String mergeFilePath)
			throws IOException {
		ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(
				mergeFilePath));
		List<File> fileList = FileUtil.getSubFiles(new File(dirPath));
		Set<String> entryNameSet = new HashSet<String>();// 解压的文件名缓存起来
		ZipEntry zipEntry = null;
		for (File jarFile : fileList) {
			if (jarFile.isDirectory() || !jarFile.getName().endsWith("jar")) {
				continue;// 只处理jar文件
			}
			if (!"".equals(jarPerfix) && !jarFile.getName().startsWith(jarPerfix)) {
				continue;//前缀必须是jarPerfix
			}
			if (!"".equals(jarPerfix_Exclude) && jarFile.getName().startsWith(jarPerfix_Exclude)) {
				continue;//前缀不能是jarPerfix_Exclude
			}

			ZipFile zipFile = new ZipFile(jarFile);
			System.out.println("\n===== process zipfile "+zipFile.getName()+" =====");
			Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
			byte[] buf = new byte[1024];
			while (zipEntrys.hasMoreElements()) {
				// 从ZipFile中得到一个ZipEntry
				zipEntry = (ZipEntry) zipEntrys.nextElement();
				if (zipEntry.isDirectory()) {
					System.out.println("Dir: " + zipEntry.getName() + " skipped..");
					continue;
				}
				System.out.println("Extracting: " + zipEntry.getName()
						+ " (Size:" + zipEntry.getSize() + " compressedSize="
						+ zipEntry.getCompressedSize()+")");
				
				if (entryNameSet.contains(zipEntry.getName())) {// 已经存在不替换
					continue;
				} else {
					entryNameSet.add(zipEntry.getName());
				}

				// 将ZipEntry加到zos中，再写入实际的文件内容
				try {
					zos.putNextEntry(zipEntry);
				} catch (Exception e) {
					System.err.println("----" + jarFile.getName() + " /"
							+ zipEntry.getName() + ":\n" + e.getMessage());
					zipEntry = null;
					continue;
				}

				// 以ZipEntry为参数得到一个InputStream，并写到OutputStream中
				InputStream is = new BufferedInputStream(zipFile
						.getInputStream(zipEntry));
				int readLen = 0;
				while ((readLen = is.read(buf, 0, 1024)) != -1) {
					zos.write(buf, 0, readLen);
				}
				is.close();
				System.out.println(" ok!");
			}
			zipFile.close();
		}
		zos.close();
	}

}
